/********************************Copyright (c)**********************************\
**
**                   (c) Copyright 2023, Main, China, QD.
**                           All Rights Reserved
**
**                                 By(wo4fisher)
**                           http://www.wo4fisher.com
**
**----------------------------------文件信息------------------------------------
** 文件名称: appTask.c
** 创建人员: wht
** 创建日期: 2023-10-25
** 文档描述:
**
**----------------------------------版本信息------------------------------------
** 版本代号: V0.1
** 版本说明: 初始版本
**
**------------------------------------------------------------------------------
\********************************End of Head************************************/
#include "ocs.h"
#include "appTask.h"
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"
#include "easyflash.h"
#include "EventRecorder.h"
#include "stdio.h"
#include <stdlib.h>

// 在OCS.H中定义
//#define O2FLOWMIN  0.6
//#define O2FLOWMAX  4.2
//#define O2FLOWSTART 3.2 

#define VALVE_OPEN_TIME 3000  //分子筛单个阀门打开持续时间
#define VALVE_OPEN_INTERVAL_TIME 500 // 分子筛一个阀门打开后，另一个阀门关闭的时间


#define MSG_TIMEOUT 0x0F

volatile float f_set;          // 开机初始流量O2FLOWMAX
volatile float f_old = 0;

volatile uint8_t o2generator_SM_state = 0;   //制氧机状态机切换变量
volatile uint8_t o2generator_OnOff_flag = 0; //制氧机启停标志，由编码器按键控制

volatile uint8_t valve_Start_flag = 0;               //分子筛阀门开启标志
volatile uint8_t valve_Sel = 0;                         //分子筛阀门交替开启选择
volatile uint8_t valve_Switch_Flag = 0;              //阀门切换标志
volatile uint32_t valve_Ticks = 0;                   //分子筛超时计时
volatile uint32_t flow_Ticks = 0;
volatile uint8_t flow_Adjust_Flag = 0;
volatile uint32_t o2concentTicks = 0;

/*******************************************************************************
** 函数名称: LCD_GUI_Init
** 功能描述: LCD GUI初始化函数
** 参数说明: None
** 返回说明: None
** 创建人员: wht
** 创建日期: 2023-10-25
**------------------------------------------------------------------------------
** 修改人员:wht
** 修改日期:
** 修改描述:
**------------------------------------------------------------------------------
********************************************************************************/
void LCD_GUI_Init ( void )
{
    uint8_t line = 100;
    LCD_ShowString ( 168, 6, "ZhiYangJi", BLUE, GREEN, 32, 0 );
    LCD_DrawLine ( 168, 40, 312, 40, WHITE );
    LCD_DrawLine ( 168, 42, 312, 42, WHITE );
    LCD_ShowString ( 35, line - 32 - 20, "LiuLiang:", BLUE, GREEN, 32, 0 );

    LCD_DrawLine ( 0, line, 480, line, WHITE );
    LCD_DrawLine ( 0, line + 1, 480, line + 1, WHITE );
    LCD_DrawLine ( 0, line + 2, 480, line + 2, WHITE );

    LCD_ShowString ( 50, line + 38, "o2Concent:", ORIGIN, GREEN, 24, 0 );
    LCD_ShowString ( 50, line + 74, "o2Flow:", ORIGIN, GREEN, 24, 0 );
    LCD_ShowString ( 50, line + 110, "o2temp:", ORIGIN, GREEN, 24, 0 );

}


/*******************************************************************************
** 函数名称: o2generator_Ctrl
** 功能描述:
** 参数说明: None
** 返回说明: None
** 创建人员: wht
** 创建日期: 2023-10-26
**------------------------------------------------------------------------------
** 修改人员:wht
** 修改日期:
** 修改描述:
**------------------------------------------------------------------------------
********************************************************************************/
void o2generator_Ctrl ( void )                                      //当前状态和开关机信号
{
    uint32_t ticks;
    switch ( o2generator_SM_state )
    {
    case 0:                                                      //停机  等待开机信号
        if ( o2generator_OnOff_flag == 1 )                        //开始制氧操作
        {
            Bsp_LedOn ( LED2 );
            Bsp_StepMotor_AdjustOpenness_f ( f_set );       //开流量阀
            f_old = f_set;
            Bsp_ValveOn ( VALVE1 );                         //开启分子筛阀门
            Bsp_ValveOff ( VALVE2 );
            valve_Sel = 0;
            Bsp_RelayOn();                                   //启动压缩机
            valve_Start_flag = 1;
            valve_Ticks = osKernelGetTickCount();           //记录当前ticks
            o2generator_SM_state = 1;
        }
        break; // case :0
    case 1:                                                    //制氧   阀门交替开			收到停信号，关
        if ( o2generator_OnOff_flag == 0 )                     //停机（停止制氧）操作
        {
            Bsp_LedOff ( LED2 );
            Bsp_RelayOff();                                    //关闭压缩机
            osDelay ( 100 ); //HAL_Delay ( 50 );
            Bsp_ValveOff ( VALVE2 | VALVE1 );               //关闭分子筛
            //Bsp_StepMotor_AdjustOpenness_f ( O2FLOWSTART ); //开到阈值O2FLOWMAX
            //f_set = O2FLOWSTART;

            o2generator_SM_state = 0;
        }
        else //继续制氧
        {
            ticks = osKernelGetTickCount();
            if ( ticks - valve_Ticks > VALVE_OPEN_TIME && valve_Switch_Flag == 0 )
            {
                valve_Sel = valve_Sel ? 0 : 1;
                if ( valve_Sel )
                {
                    Bsp_ValveOn ( VALVE2 );                 //开启分子筛阀门
                }
                else
                {
                    Bsp_ValveOn ( VALVE1 );                 //开启分子筛阀门
                }
                valve_Ticks = ticks;
                valve_Switch_Flag = 1;
            }
            if ( ticks - valve_Ticks > VALVE_OPEN_INTERVAL_TIME && valve_Switch_Flag == 1 )
            {
                if ( valve_Sel )
                {
                    Bsp_ValveOff ( VALVE1 );
                }
                else
                {
                    Bsp_ValveOff ( VALVE2 );
                }
                valve_Switch_Flag = 0;
            }
						//判断氧气浓度 低了蜂鸣器响
						if(f1>90.0)
							o2concentTicks = osKernelGetTickCount();
						else 
						{
								if(osKernelGetTickCount()-o2concentTicks >60000)
									Bsp_Beep(150);
						}						
        }
        break;                                                // end case :1
    }
}
/*******************************************************************************
** 函数名称: Flow_Ctrl
** 功能描述: 流量调节
** 参数说明: msg 传入按键值
** 返回说明: None
** 创建人员: wht
** 创建日期: 2023-10-26
**------------------------------------------------------------------------------
** 修改人员:wht
** 修改日期:
** 修改描述:
**------------------------------------------------------------------------------
********************************************************************************/
void Flow_Ctrl ( uint8_t msg )
{
    switch ( msg )
    {
    case ENCODERKEYPRE:                  //- 编码器
        if ( o2generator_SM_state == 1 )
        {
            f_set -= 0.1;
            if ( f_set < ( O2FLOWMIN + 0.2 ) )
                f_set = ( O2FLOWMIN + 0.2 );
            flow_Ticks = osKernelGetTickCount();
            flow_Adjust_Flag = 1;
        }
        break;
    case ENCODERKEYNEXT:                  //+ 编码器
        if ( o2generator_SM_state == 1 )
        {
            f_set += 0.1;
            if ( f_set > O2FLOWMAX )
                f_set = O2FLOWMAX;
            flow_Ticks = osKernelGetTickCount();
            flow_Adjust_Flag = 1;
        }
        break;
    case ENCODERKEYCLICK:                  //按键按下
        o2generator_OnOff_flag = o2generator_OnOff_flag ? 0 : 1;
        break;
    default:
        break;
    }
}

/*******************************************************************************
** 函数名称: test_blob_env
** 功能描述: 启动次数flash保存测试
** 参数说明: None
** 返回说明: None
** 创建人员: wht
** 创建日期: 2023-10-26
**------------------------------------------------------------------------------
** 修改人员:wht
** 修改日期:
** 修改描述:
** 1.ef_get_env_blob 读取环境变量
** size_t ef_get_env_blob(const char *key, void *value_buf, size_t buf_len, size_t *save_value_len);
** key：环境变量名称
** value_buf：存放环境变量的缓冲区
** buf_len：该缓冲区的大小
** save_value_len：返回该环境变量实际存储在 flash 中的大小
** 返回值：成功存放至缓冲区中的数据长度
** eg.
** 环境变量长度未知，先获取 Flash 上存储的实际长度
 ** ef_get_env_blob("wifi_passwd", NULL, 0, &len);
 ** 获取环境变量
**  ef_get_env_blob("wifi_passwd", wifi_passwd, len, NULL);
**
** 2. ef_set_env_blob 设置环境变量
** EfErrCode ef_set_env_blob(const char *key, const void *value_buf, size_t buf_len);
** 增加 ：当环境变量表中不存在该名称的环境变量时，则会执行新增操作；
** 修改 ：入参中的环境变量名称在当前环境变量表中存在，则把该环境变量值修改为入参中的值；
** 删除：当入参中的value为NULL时，则会删除入参名对应的环境变量。
** 其中参数的意义如下：
** key：环境变量名称
** value_buf：环境变量值缓冲区
** buf_len：缓冲区长度，即值的长度
**------------------------------------------------------------------------------
********************************************************************************/
void test_blob_env ( void )
{
    uint32_t i_boot_times = NULL;
    uint8_t len = 0;

    /* get the boot count number from Env */
    len =  ef_get_env_blob ( "boot_times", &i_boot_times, 1, NULL );
//len =  ef_get_env_blob ( "f_set", &f_set, 8, NULL );
    /* boot count +1 */
	printf("i_boot_times=%u\n",i_boot_times);
    i_boot_times ++;
//	f_set =2.4;
    /* set and store the boot count number to Env */
    ef_set_env_blob ( "boot_times", &i_boot_times, 1 );
//	ef_set_env_blob ( "f_set", &f_set, 8 );
    ef_save_env();
}

extern osMessageQueueId_t  Encoder_QueueHandle;

/*******************************************************************************
** 函数名称: MainTaskFun
** 功能描述: 工作调度主任务
** 参数说明: argument: [输入/出]
** 返回说明: None
** 创建人员: wht
** 创建日期: 2023-10-25
**------------------------------------------------------------------------------
** 修改人员:wht
** 修改日期:
** 修改描述:
**------------------------------------------------------------------------------
********************************************************************************/
void MainTaskFun ( void *argument )
{
    /* USER CODE BEGIN MainTaskFun */
    uint8_t encoder_Msg;
    uint32_t len;
	
    taskENTER_CRITICAL();
    if ( easyflash_init() != EF_NO_ERR )
    {
        for ( ;; )
            Bsp_Beep ( 150 ); //初始化失败，beep一直响
    }
    taskEXIT_CRITICAL();

    Bsp_Ocs_Start_Receive_It();                         //开启氧气传感器串口中断接收

    taskENTER_CRITICAL();
    //读取环境变量f_set的值 先读取存储长度，再读取保存的值
//    ef_get_env_blob ( "f_set", NULL, 0, &len );
    ef_get_env_blob ( "f_set", &f_set, 8, NULL );
    taskEXIT_CRITICAL();

    stepMotor_CurrentOpenness = Bsp_StepMotor_Calc_Openness ( f_set ); //根据设定流量计算开度  适用于开度和设定流量无法保存

    /* Infinite loop */
    for ( ;; )
    {
        o2generator_Ctrl();
        if ( osMessageQueueGet ( Encoder_QueueHandle, &encoder_Msg, NULL, 0 ) == osOK ) //有按键按下，没处理
            Flow_Ctrl ( encoder_Msg );
        if ( osKernelGetTickCount() - flow_Ticks > 2000 && flow_Adjust_Flag == 1 )
        {
            Bsp_StepMotor_AdjustOpenness_f ( f_set ); //调整 流量阀
		
            taskENTER_CRITICAL();
						// 保存设定流量到easyflash
            ef_set_env_blob ( "f_set", &f_set, 8 );
						ef_save_env();
            taskEXIT_CRITICAL();
            
						flow_Adjust_Flag = 0;
        }
        osDelay ( 20 );
    }
    /* USER CODE END MainTaskFun */
}

/*******************************************************************************
** 函数名称: EncoderTaskFun
** 功能描述: 编码器读取并传键值到Queue
** 参数说明: argument: [输入/出]
** 返回说明: None
** 创建人员: wht
** 创建日期: 2023-10-25
**------------------------------------------------------------------------------
** 修改人员:wht
** 修改日期:
** 修改描述:
**------------------------------------------------------------------------------
********************************************************************************/
void EncoderTaskFun ( void *argument )
{
    uint8_t msg_type;
    /* USER CODE BEGIN EncoderTaskFun */
    Bsp_Encoder_Start ( ENCODERCNTINIT );//开启定时器编码器
			/* 初始化 EventRecorder 并开启 */
    EventRecorderInitialize ( EventRecordAll,1U );
    EventRecorderStart();
	osDelay ( 500 );
//    测试easyFlash
    taskENTER_CRITICAL();
     if (easyflash_init() == EF_NO_ERR)
    {
        /* test Env demo */
        test_blob_env();
    }
    taskEXIT_CRITICAL();

    osDelay ( 50 );
    /* Infinite loop */
    for ( ;; )
    {
        msg_type = Bsp_Encoder_Task();
        if ( msg_type != ENCODERKEYNONE )
        {
            osMessageQueuePut ( Encoder_QueueHandle, &msg_type, NULL, 0 );
            Bsp_BeepOn();
            osDelay ( 30 );
            Bsp_BeepOff();
            if ( msg_type == ENCODERKEYCLICK )
                osDelay ( 100 );
        }
        osDelay ( 50 );
    }
    /* USER CODE END EncoderTaskFun */
}

extern osMutexId_t f_Disp_MutexHandle;
/*******************************************************************************
** 函数名称: GuiTaskFun
** 功能描述: GUI 任务
** 参数说明: argument: [输入/出]
** 返回说明: None
** 创建人员: wht
** 创建日期: 2023-10-25
**------------------------------------------------------------------------------
** 修改人员:wht
** 修改日期:
** 修改描述:
**------------------------------------------------------------------------------
********************************************************************************/
void GuiTaskFun ( void *argument )
{
    /* USER CODE BEGIN GuiTaskFun */
    LCD_Init();
    LCD_Fill ( 0, 0, LCD_W, LCD_H, GREEN );
    LCD_GUI_Init();
    osDelay ( 50 );
		
    /* Infinite loop */
    for ( ;; )
    {
        osMutexAcquire ( f_Disp_MutexHandle, 100 );
        LCD_ShowFloatNum1 ( 182, 50, f_set, 4, BLUE, GREEN, 32 );
        osMutexRelease ( f_Disp_MutexHandle );
				if(o2generator_OnOff_flag==1)
					printf(",%.2f",f1);
        LCD_ShowFloatNum1 ( 172, 138, f1, 4, ORIGIN, GREEN, 24 );
        LCD_ShowFloatNum1 ( 136, 174, f2, 4, ORIGIN, GREEN, 24 );
        LCD_ShowFloatNum1 ( 136, 210, f3, 4, ORIGIN, GREEN, 24 );
        osDelay ( 1000 );
    }
    /* USER CODE END GuiTaskFun */
}





/********************************End of File************************************/
